<?php

    /*
        {{iconlink href="/cabinet/?logout" iconclass="undoicon" title="Закрыть аккаунт" text=" Выйти"}}
        Actions format: /action.sevenchances.deletemycomment&id=25
    */

    class MikronClass
    {

        public $Config;
        public $SiteManager; //  SiteManager();
        public $Queries; // Queries;
        public $Schema; // MikronSchemas;
        public $Site; // mikron_site;
        public $Exceptions; // MikronExceptions;
        public $Constants; // MikronConstants;
        public $EntityManager; // entitymanager_class;
        public $Enumerators; // enums_class;
        public $OperatingInstructions; // OperatingInstructions;
        public $CSS; // CSSModule;
        public $JS; // JSModule; // JavaScript файлы добавляемые к странице
        public $TemplateMaker;// TemplateMaker;
        public $Handlers; // HandlerClass;
        public $Modules;
        public $Cache; //  cache_control_class();
        public $Tools; // FunctionsClass();
        public $Users; // UsersClass();
        public $Roles; // RolesClass();
        public $ACL; // Mikron_Acl();
        public $Applications; // new ApplicationsClass();
        public $Page; //

        public $Counter; //
        public $Crypt; // CryptorClass();
        public $Graphics; // MikronGraphics();

        public $global_admincenter_menu = Array();

        public function __construct()
        {
            $this->Config = new MikronConfigManager();
            $this->SiteManager = new MikronSiteManager($this);
            // Функции, наличие которых обязательно для Mikron
            $need_functions = $this->Config->GetList('need_functions');
            foreach($need_functions as $function)
            {
                if(!function_exists($function->name))
                {
                    // Сообщение выводимое пользователю, при отсутствии данной функции
                    CriticalError($function->getString('message'));
                }
            }
        }

        public function Initialize()
        {
            $this->Schema = new MikronSchemas($this);
            $this->Counter = new MikronCounter($this);
            $this->Crypt = new CryptorClass($this);
            $this->Queries = new Queries($this);
            $this->Enumerators = new enums_class();
            $this->EntityManager = new entitymanager_class($this);
            $this->Exceptions = new MikronExceptions();
            $this->TemplateMaker = new TemplateMaker();
            $this->Constants = new MikronConstants($this);
            $this->OperatingInstructions = new OperatingInstructions();
            $this->CSS = new CSSModule($this);
            $this->JS = new JSModule($this);
            $this->Handlers = new HandlerClass();
            $this->Modules = new ModulesClass($this);
            $this->Cache = new cache_control_class();
            $this->Tools = new MikronToolsClass($this);
            $this->Roles = new RolesClass();
            $this->Applications = new ApplicationsClass($this);
            $this->Graphics = new MikronGraphics();
            $this->Page = new MikronPageClass($this);
            // ACL
            $this->ACL = new Mikron_Acl($this);
        }
        
        /**
        * Fast access to T_VARIABLES values
        * 
        * @param mixed $code
        */
        public function getVariable($code, $default_value = null)
        {
            $var = $this->Queries->QueryOne('T_VARIABLES', null, new Criterion('code', $code), null, null, null, false, new ReturnAttributes('textvalue'));
            if($var instanceof T_VARIABLES)
            {
                return $var->textvalue->value;
            }
            return $default_value;
        }

        function InitUsers()
        {
            $this->Users = new UsersClass($this);
        }

        // Меню админки (в этот массив можно добавить свой пункт меню функцией addmenu()
        // с любого места CMS до инклюда menu.inc). Это удобней сделать в файле site_main.inc
        function addmenu($place, $url)
        {
            $this->global_admincenter_menu[$place] = Array($url, $place);
        }
        
        public static function ClassIsFind($classname)
        {
            if(class_exists($classname))
            {
                return true;
            }
            echo sprintf('<font color="red">Ошибка. Отсутсвует класс %s»,
                возможно требуется обновления схемы.</font>', $classname);
            return false;
        }
        
        public static function getActionStatus($action)
        {
            if(!isset($_GET['action']))
            {
                return null;
            }
            if(isset($_GET['ok']))
            {
                return 'ok';
            }            
            if(isset($_GET['error']))
            {
                return $_GET['error'];
            }
            return null;
        }

    }

   // обработчик управляющей инструкции «userform»
    function OperatingInstruction_UserForm($parameters)
    {

        global $mikron;
        
        /*try
        {
            $dataObject = DataObject::ArrayToDataObject($parameters);
            $mikron->EntityManager->ShowFormForUsersEx($dataObject);
        }
        catch(Exception $ex)
        {
            echo '<font color="red">', $ex->getMessage(), '</font>';
        }
        return null;*/

        $onsubmit = null;

        $inputsize = null;
        $textarea_cols = null;
        $textarea_rows = null;
        $cellspacing = null;
        $cellpadding = null;
        
        $htmlform = null;
        if(array_key_exists('htmlform', $parameters)){$htmlform = $parameters['htmlform'];}
        if(array_key_exists('textareacols', $parameters)){$textarea_cols = $parameters['textareacols'];}
        if(array_key_exists('textarearows', $parameters)){$textarea_rows = $parameters['textarearows'];}
        if(array_key_exists('cellspacing', $parameters)){$cellspacing = $parameters['cellspacing'];}
        if(array_key_exists('cellpadding', $parameters)){$cellpadding = $parameters['cellpadding'];}

        $classname = $parameters['entityname'];
        $id = (int)$mikron->Tools->GetParam($parameters, 'id', 0);
        $caption = $mikron->Tools->GetParam($parameters, 'caption', null);
        $formname = $mikron->Tools->GetParam($parameters, 'name', null);
        $signature = $mikron->Tools->GetParam($parameters, 'signature', null);
        $formid = $mikron->Tools->GetParam($parameters, 'formid', null);
        $submit_caption = $mikron->Tools->GetParam($parameters, 'submit_caption', null);
        $formclass = $mikron->Tools->GetParam($parameters, 'class', null);
        $captcha_need = (int)$mikron->Tools->GetParam($parameters, 'captcha', 0) == 1;
        $columns = (int)$mikron->Tools->GetParam($parameters, 'columns', 2);
        $error_page = $mikron->Tools->GetParam($parameters, 'errorpage', null);
        $return_to_page = $mikron->Tools->GetParam($parameters, 'returnpage', null);
        $button_caption = $mikron->Tools->GetParam($parameters, 'button_caption', null);
        $inputsize = $mikron->Tools->GetParam($parameters, 'inputsize', null);
        $hide_labels = (int)$mikron->Tools->GetParam($parameters, 'hide_labels', 0) == 1;

        $require_double_password_field = true;

        if(array_key_exists('validate', $parameters))
        {
            $formkey = md5(MikronTimer::getmicrotime() + mt_rand(0, 9999999999));
            echo sprintf('<script type="text/javascript">
                var v%s = {%s};
            </script>', $formkey, $parameters['validate']);
            $onsubmit = "validate2(this, v".$formkey.")";
        }
        if(array_key_exists("onsubmit", $parameters))
        {
            if(is_null($onsubmit))
            {
                $onsubmit = 'return '.$parameters['onsubmit'].';';
            }
            else
            {
                $onsubmit = "if($onsubmit){return ".$parameters['onsubmit'].";}else{return false;}";
            }
        }
        else
        {
            if(!is_null($onsubmit))
            {
                $onsubmit = 'return '.$onsubmit.';';
            }
        }
        if(!class_exists($classname))
        {
            return null;
        }
        if($id < 1){$id = null;}
        if(array_key_exists('double_password_field', $parameters))
        {
            $require_double_password_field = $parameters['double_password_field'];
        }
        $processor = $_SERVER['REQUEST_URI'];
        if(array_key_exists('processor', $parameters))
        {
            if(!$mikron->Tools->IsNullOrEmpty($parameters['processor']))
            {
                $processor = $parameters['processor'];
            }
        }
        $e = new $classname($id);
        try
        {
            $mikron->EntityManager->ShowFormForUsers($e, $caption, false, $captcha_need,
                $return_to_page, false, $processor, $onsubmit, $formname,
                $formclass, $formid, $error_page, $submit_caption, $columns, $button_caption, 240, $signature,
                $require_double_password_field,
                $inputsize, $textarea_cols, $textarea_rows, $cellspacing, $cellpadding, $htmlform,
                $hide_labels);
        }
        catch(Exception $ex)
        {
            echo '<font color="red">', $ex->getMessage(), '</font>';
        }
    }

    // Handlers.
    // Обработчики событий Mikron.
    class handler_object
    {
        public $processor = null;
        public $object = null;
        public $entities = Array();
        function __construct($processor, &$object = null, $for_entities = null)
        {
            if(!is_array($for_entities))
            {
                $for_entities = Array($for_entities);
            }
            $this->processor = $processor;
            $this->object = $object;
            $this->entities = $for_entities;
        }
    }
    
    define('HANDLER_SAVE', 'Save');
    define('HANDLER_DELETE', 'Delete');
    define('HANDLER_REGISTRATION', 'Registration');
    define('HANDLER_AUTHORIZATION', 'Authorization');
    define('HANDLER_PAGE_COMPLETE', 'PageComplete');
    define('HANDLER_PAGE_PRINTED', 'PagePrinted');
    define('HANDLER_TOSTRING', 'ToString');

    class HandlerClass
    {
        private $handlers = Array();

        /**
        * Get handlers collection
        * 
        * @param mixed $hanler_operation HANDLER_ const goes here
        */
        public function Handlers($hanler_operation)
        {
            if(array_key_exists($hanler_operation, $this->handlers))
            {
                return $this->handlers[$hanler_operation];
            }
            return Array();
        }

        function AddRegistrationHandler($processor, &$object = null)
        {
            $this->handlers[HANDLER_REGISTRATION][] = new handler_object($processor, $object);
        }
        function AddAuthorizationHandler($processor, &$object = null)
        {
            $this->handlers[HANDLER_AUTHORIZATION][] = new handler_object($processor, $object);
        }
        function AddSaveHandler($processor, $for_entities, &$object = null)
        {
            $this->handlers[HANDLER_SAVE][] = new handler_object($processor, $object, $for_entities);
        }
        function AddToStringHandler($processor, $for_entities, &$object = null)
        {
            $this->handlers[HANDLER_TOSTRING][] = new handler_object($processor, $object, $for_entities);
        }
        /**
        * Run handler before gzipping page
        * 
        * @param mixed $processor Function name with one argument - page content
        * @param mixed $object Object with $processor function. If null then $object = $mikron->Site
        */
        function AddPageCompleteHandler($processor, &$object = null)
        {
            $this->handlers[HANDLER_PAGE_COMPLETE][] = new handler_object($processor, $object);
        }
        function AddPagePrintedHandler($processor, &$object = null)
        {
            $this->handlers[HANDLER_PAGE_PRINTED][] = new handler_object($processor, $object);
        }

        // Handler sterters
        function PagePrintedHandlersRun(& $miniBB_gzipper_in)
        {
            // PagePrinted handlers run
            $handlers = $this->Handlers(HANDLER_PAGE_PRINTED);
            foreach($handlers as $handler)
            {
                $processor = $handler->processor;
                $object = $handler->object;
                if(is_null($object))
                {
                    $object = $mikron->Site;
                }
                $object->$processor($miniBB_gzipper_in);
            }
        }

        function PageCompleteHandlersRun(& $miniBB_gzipper_in)
        {
            return;
            // PageComplete handlers run
            $handlers = $this->Handlers(HANDLER_PAGE_COMPLETE);
            foreach($handlers as $handler)
            {
                $processor = $handler->processor;
                $object = $handler->object;
                if(is_null($object))
                {
                    $object = $mikron->Site;
                }
                $object->$processor($miniBB_gzipper_in);
            }
        }

    }

    class ModulesClass
    {
        private $mikron;
        private static $loaded_modules = Array();       
        private $o_modules; // супермодули
        
        public function __construct($mikron)
        {
            $this->mikron = $mikron;
        }
        
        public function Initialize()
        {
            static $initialized = false;
            if($initialized)
            {
                #warning написать сообщение о том, что модули уже были проинициализированы ранее и второй раз этого делать нельзя
                throw new Exception('Modules was initialized.');
            }
            $initialized = true;
            foreach($this->mikron->Config->GetList('loadable_modules') as $loadableModule)
            {
                $this->LoadModule($loadableModule->name);
            }
        }

        public static function LoadModule($name, $specify_module_path = null)
        {
            global $mikron;
            if(array_key_exists($name, self::$loaded_modules))
            {
                return true;
            }
            try
            {
                $file = is_null($specify_module_path)?constant('CMS_DIRECTORY').'/../modules/'.$name.'/module.php':$specify_module_path;
                if(!file_exists($file))
                {
                    $file2 = is_null($specify_module_path)?constant('CMS_DIRECTORY').'/../modules/'.$name.'/module.inc':$specify_module_path;
                    if(file_exists($file2))
                    {
                        $file = $file2;
                    }
                    else
                    {
                        throw new Exception('Файл модуля '.$name.' не найден.');
                    }
                }
                require_once($file);
                self::$loaded_modules[$name] = Array('file' => $file);
                return true;
            }
            catch(Exception $ex)
            {
                CriticalError('Не удалось загрузить модуль '.$name.'. '.$ex->getMessage(), null, true);
                return false;
            }
        }

        /**
        *  Супермодули
        */
    
        private function AddModulesXML($xml_file)
        {
            $module_path = dirname($xml_file).'/module.inc';
            $dom = new DOMDocument();
            $dom->load($xml_file);
            $tags = $dom->getElementsByTagName('modules');
            if($tags->length == 0)
            {
                CriticalError("Не удалось разобрать файл модулей. Неверная схема.", null, true);
            }
            $o_modules = Array();
            foreach($tags as $tag)
            {
                // разбор справочников
                $modules = $tag->getElementsByTagName('module');
                foreach($modules as $module)
                {
                    if(!$module->hasAttribute('name') || !$module->hasAttribute('description') || !$module->hasAttribute('code'))
                    {
                        throw new Exception('Неверное описание модуля '.basename($xml_file));
                    }
                    $module_code = $module->getAttribute('code');
                    $module_name = $module->getAttribute('name');
                    $module_description = $module->getAttribute('description');
                    $operations_tag = $module->getElementsByTagName('operations');
                    $o_operations = Array();
                    foreach($operations_tag as $operations)
                    {
                        $operation_tag = $operations->getElementsByTagName('operation');
                        foreach($operation_tag as $operation)
                        {
                            if(!$operation->hasAttribute('name') || !$operation->hasAttribute('description'))
                            {
                                throw new Exception('Неверное описание операции модуля '.basename($xml_file));
                            }
                            $name = $operation->getAttribute('name');
                            $description = $operation->getAttribute('description');
                            $o_operations[] = new Mikron_Module_Operation($name, $description);
                        }
                    }
                    $this->o_modules[] = new Mikron_Module_Information($module_code, $module_name, $module_description, $o_operations, $module_path);
                }
            }
        }
   
        private function ModuleExists($code)
        {
            static $modules = null;
            if(is_null($modules))
            {
                $modules = $this->mikron->Queries->Query('T_MODULE');
            }
            while($module = $modules->fetch())
            {
                if($module->code->value == $code)
                {
                    return $module;
                }
            }
            return null;
        }

        /**
        * Обновление списка модулей. Вызывается по команде
        * из администраторсокй консоли управления модулями.
        * 
        * @param mixed $mikron
        */
        function Refresh($mikron)
        {
            $dir = dirname(__FILE__).'/../super_modules/';
            $dh = opendir($dir);
            while (($file = readdir($dh)) !== false)
            {
                switch($file)
                {
                    case '.': case '..':
                        break;
                    default:
                        $file = $dir . $file;
                        if(is_dir($file))
                        {
                            $module = $file.'/module.xml';
                            if(!file_exists($module))
                            {
                                throw new Exception('Модуль не найден '.$module);
                            }
                            $module = realpath($module);
                            $this->AddModulesXML($module);
                        }
                }
            }
            closedir($dh);
            Queries::StartTransaction();
            try
            {
                $this->UpdateLoadedModulesInfo();
                Queries::CommitTransaction();
            }
            catch(Exception $ex)
            {
                Queries::RollbackTransaction();
                throw new Exception("Не удалось обновить модули. Ошибка: ".$ex->getMessage());
            }
        }

        /**
        * Процедура выполняется после процедуры Refresh() (обновление списка модулей).
        */
        private function UpdateLoadedModulesInfo()
        {
            $updated_objects = Array();
            // $omodule = new Mikron_Module_Information();
            foreach($this->o_modules as $omodule)
            {

                // Информация вычитанного из XML модуля
                $name = $omodule->Name();
                $code = $omodule->Code();
                $path = str_replace(dirname(__FILE__), null, realpath($omodule->Path()));
                $description = $omodule->Description();
                $operations = $omodule->Operations();

                // Поиск существующего модуля
                $module = $this->ModuleExists($code);

                // Если в системе не зарегистрирован данный модуль
                if(!is_object($module))
                {
                    // Регистрация нового модуля в системе
                    $module = new T_MODULE();
                    $module->name->value = $name;
                    $module->code->value = $code;
                    $module->description->value = $description;
                    $module->installed->value = 0;
                    $module->path->value = $path;
                    $this->mikron->EntityManager->Save(Array($module), false);
                    $updated_objects[] = $module;
                }
                else
                {
                    if(($module->path->value != $path) || 
                        ($module->name->value != $name) || 
                        ($module->description->value != $description) || 
                        ($module->code->value != $code))
                    {
                        $module->name->value = $name;
                        $module->code->value = $code;
                        $module->description->value = $description;
                        $module->path->value = $path;
                        $updated_objects[] = $module;
                    }
                }

                $old_operations = Array();
                $new_operations = Array();
                foreach($module->operations->value as $module_operation)
                {
                    $old_operations[] = $module_operation->code->value;
                }
                foreach($operations as $module_operation)
                {
                    $new_operations[] = $module_operation->Code();
                }
                

                // Удаление лишних операций
                // пробегаемся по существующим операциям
                foreach($module->operations->value as $module_operation)
                {
                    // Если их нет в новом списке, то удаляем их
                    $operation_name = $module_operation->code->value;
                    if(!in_array($operation_name, $new_operations))
                    {
                        $this->mikron->EntityManager->DeleteEntity('T_OPERATION', $module_operation->id);
                    }
                }
                
                // Пробегаемся по новой схеме модуля
                foreach($operations as $operation)
                {
                    // Если операции нет в старой схеме, то создаем новую
                    $operation_code = $operation->Code();
                    if(!in_array($operation_code, $old_operations))
                    {
                        $o = new T_OPERATION();
                        $o->code->value = $operation_code;
                        $o->name->value = $operation->Name();
                        $o->module->value = $module->id;
                        $updated_objects[] = $o;
                    }
                }

                // Пробегаемся по новой схеме модуля
                foreach($operations as $operation)
                {
                    // Если данные обновлены
                    $operation_name = $operation->Code();
                    $operation_description = $operation->Name();

                    if(count($module->operations->value) > 0)
                    {
                        foreach($module->operations->value as $mop)
                        {
                            $mop_name = $mop->name->value;
                            if($mop_name == $operation_name)
                            {
                                $mop_description = $mop->description->value;
                                if($mop_description != $operation_description)
                                {
                                    $mop->description->value = $operation_description;
                                    $updated_objects[] = $mop;
                                }
                                break;
                            }
                        }
                    }
                }
            }
            /*
            echo '<pre>';
            echo count($updated_objects);
            exit;
            */
            $this->mikron->EntityManager->Save($updated_objects, false);
        }
    }

    class JSModule
    {
        public $Files = Array();
        private $mikron;
   
        public function __construct(MikronClass $mikron)
        {
            $this->mikron = $mikron;
            $mikron->OperatingInstructions->AddFunction('JSFiles', 'OperatingInstruction_JSFiles', $this);
        }

        public function OperatingInstruction_JSFiles($parameters)
        {
            foreach($this->mikron->JS->Files as $jsfile)
            {
                $file = str_replace("\\", '/', $jsfile['file']);
                $comment = $jsfile['comment'];
                $file = str_replace($_SERVER['DOCUMENT_ROOT'], null, $file);
                ?><script type="text/javascript" src="<?php echo $file; ?>"><?php if(!is_null($comment)){echo $comment;} ?></script><?php
            }
        }

        function PrintFiles()
        {
            foreach($this->Files as $jsfile)
            {
                $file = str_replace("\\", "/", $jsfile['file']);
                $comment = $jsfile['comment'];
                $file = str_replace($_SERVER['DOCUMENT_ROOT'], null, $file);
                ?><script type="text/javascript" src="<?php echo $file; ?>"><?php if(!is_null($comment)){echo "/* $comment */";} ?></script><?php
            }
        }

        function AddFile($path, $comment = null)
        {
            if(!file_exists($path))
            {
                throw new Exception('Javascript файл не найден '.$path);
                return false;
            }
            if(!is_null($comment))
            {
                $comment = str_replace('/*', null, $comment);
                $comment = str_replace('*/', null, $comment);
                $comment = strip_tags($comment);
            }
            $this->Files[] = Array('file' => $path, 'comment' => $comment);
            return true;
        }
    }

    class CSSModule
    {
        // CSS буфер, в который могут добавлять все
        // Затем он замещает собой метатег {{CSSSTYLE}}
        private $CSSStyle = null;
        private $mikron = null;
        private $style_files = Array();
        function __construct(MikronClass $mikron)
        {
            $this->mikron = $mikron;
        }
        function Content()
        {
            $files = Array();
            foreach($this->style_files as $sf)
            {
                $sf_path = $sf['file'];
                $sf_comment = $sf['comment'];
                $sf_comment = str_replace('<!--', null, $sf_comment);
                $sf_comment = str_replace('-->', null, $sf_comment);
                $sf_path = WWWDirName($sf_path).'/'.basename($sf_path);
                $files[] = sprintf('<!-- %s -->'."\r\n".'<link rel="stylesheet" href="%s" type="text/css" />', $sf_comment, $sf_path);
            }
            return implode("\r\n", $files)."\r\n".'<style type="text/css">'.$this->CSSStyle.'</style>';
        }
        function AddFile($file, $comment = null)
        {
            if(!file_exists($file))
            {
                throw new Exception('Style file not found. '.$file);
            }
            $file = realpath($file);
            $this->style_files[] = Array("comment"=>$comment, "file"=>$file);
        }
        function AddFromFile($path, $comment = null)
        {
            if(!file_exists($path))
            {
                return false;
            }
            $css = file_get_contents($path);
            return $this->Add($css, $comment);
        }
        function Add($csscode, $comment = null)
        {
            if(!is_null($comment))
            {
                $comment = str_replace("/*", null, $comment);
                $comment = str_replace("*/", null, $comment);
                $comment = strip_tags($comment);
                $this->CSSStyle .= "/* $comment */\r\n";
            }
            $this->CSSStyle .= $csscode."\r\n";
            return true;
        }
    }

    class TemplateMaker
    {
        /* Smarty */
        public $smarty; // = Smarty;
        function __construct()
        {

            /**
            * Warning: +5ms to load time
            */
            
            // miky
            define('MIKY_DIR', constant('MIKRON_DIRECTORY')."/lib/miky/");
            require_once(constant('MIKY_DIR')."miky.class.php");
            $this->smarty = new Miky();
            
            // quicky
            /*
            define('QUICKY_DIR', constant('MIKRON_DIRECTORY')."/lib/quicky/");
            require_once(constant('SMARTY_DIR')."Quicky.class.php");
            $this->smarty = new Quicky();
            $this->smarty->compiler_prefs['interpritate_varname_params'] = true;
            $this->smarty->template_dir = constant('SMARTY_DIR')."templates/";
            $this->smarty->compile_dir = constant('SMARTY_DIR')."templates_c/";
            $this->smarty->config_dir = constant('SMARTY_DIR')."configs/";
            $this->smarty->cache_dir = constant('SMARTY_DIR')."cache/";
            $this->smarty->caching = false;
            $this->smarty->left_delimiter = "{{";
            $this->smarty->right_delimiter = "}}";
            $this->smarty->error_reporting = E_ALL;
            */

            // Smarty
            /*
            define('SMARTY_DIR', constant('MIKRON_DIRECTORY')."/lib/smarty/");
            require_once(constant('SMARTY_DIR')."Smarty.class.php");
            $this->smarty = new Smarty();
            $this->smarty->template_dir = constant('SMARTY_DIR')."templates/";
            $this->smarty->compile_dir = constant('SMARTY_DIR')."templates_c/";
            $this->smarty->config_dir = constant('SMARTY_DIR')."configs/";
            $this->smarty->cache_dir = constant('SMARTY_DIR')."cache/";
            $this->smarty->error_reporting = E_ALL;
            $this->smarty->caching = false;
            $this->smarty->left_delimiter = "{{";
            $this->smarty->right_delimiter = "}}";
            */

        }
    }
    
    class MikronDateTime
    {

        function ToOADate($unixtime)
        {
            return $this->ToOADateMSSQL($unixtime) + 2;
        }

        function ToOADateMSSQL($unixtime)
        {
            $time_percent = $unixtime - strtotime(date('d-m-Y', $unixtime));
            $time_percent /= 86400;
            $unixtime = strtotime(date('Y-m-d H:i:s', $unixtime).' UTC');
            $days_after_01_01_1900 = 25567;
            $seconds_per_day = 86400;
            $days = $unixtime / $seconds_per_day + 25567;
            return $days + $time_percent;
        }

        function FromOADateMSSQL($oa_mssql_datetime)
        {
            /**
            * -10800 — strtotime('1970-1-1');
            * 25567 — кол-во дней от 01-01-1900 до 01-01-1970
            */
            $days = (int)$oa_mssql_datetime;
            $day_seconds_left_percent = $oa_mssql_datetime - $days;
            $diff = strtotime('01/01/2000 UTC') - strtotime('01/01/2000') + 3600;
            return  ($days  - 25567  + $day_seconds_left_percent) * 86400 - $diff;
        }

        public static function DateDiff($interval,$date1,$date2)
        {
            // получает количество секунд между двумя датами
            $timedifference = $date2 - $date1;
            switch ($interval)
            {
                case 'w':
                $retval = bcdiv($timedifference,604800);
                break;
                case 'd':
                $retval = bcdiv($timedifference,86400);
                break;
                case 'h':
                $retval = bcdiv($timedifference,3600);
                break;
                case 'n':
                $retval = bcdiv($timedifference,60);
                break;
                case 's':
                $retval = $timedifference;
                break;
            }
            return $retval;
        }

        public static function BeautifulWeekDayName($date, $short = true)
        {
            if($short)
            {
            $DaysOfWeek = array("Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"); 
            }
            else
            {
            $DaysOfWeek = array("Воскресение", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"); 
            }
            $arr = getdate($date);
            return $DaysOfWeek[$arr['wday']];
        }

        public static function BeautifulDate($date, $showYear = true, $short = false)
        {
            $months = array("Января","Февраля","Марта","Апреля","Мая","Июня","Июля","Августа","Сентября","Октября","Ноября","Декабря");
            $months2 = array("янв","фев","мар","апр","мая","июн","июл","авг","сен","окт","ноя","дек");
            if($short){$months=$months2;}
            $day = date('j', $date);
            $month = date('n', $date);
            $mth = $months[$month-1];
            $year = date('Y', $date);
            $ret = $day.' '.$mth;
            if($showYear){$ret .= ' '.$year;}
            return $ret;
        }

        public static function DateAdd($interval, $number, $date)
        {
            $date_time_array = getdate($date);
            $hours = $date_time_array['hours'];
            $minutes = $date_time_array['minutes'];
            $seconds = $date_time_array['seconds'];
            $month = $date_time_array['mon'];
            $day = $date_time_array['mday'];
            $year = $date_time_array['year'];
            switch ($interval) {
            case 'yyyy':
            $year+=$number;
            break;
            case 'q':
            $year+=($number*3);
            break;
            case 'm':
            $month+=$number;
            break;
            case 'y':
            case 'd':
            case 'w':
            $day+=$number;
            break;
            case 'ww':
            $day+=($number*7);
            break;
            case 'h':
            $hours+=$number;
            break;
            case 'n':
            $minutes+=$number;
            break;
            case 's':
            $seconds+=$number; 
            break; 
            }
            $timestamp= mktime($hours,$minutes,$seconds,$month,$day,$year);
            return $timestamp;
        }
    }

    class MikronToolsClass
    {
        
        public $DateTime;
        public $SiteMenu;
        public $String;
        
        function __construct(MikronClass & $mikron)
        {
            $mikron->Handlers->AddPageCompleteHandler('PageCompleteHandler', $this);
            $this->DateTime = new MikronDateTime();
            $this->SiteMenu = new SiteMenuClass($mikron);
            $this->String = new MikronString();
        }
        
        /**
        * ReflectionObject and return all object properties
        * 
        * @param mixed $object
        */
        public function getPropertyNames($object)
        {
            $rc = new ReflectionObject($object);
            $names = array();
            while ($rc instanceof ReflectionClass)
            {
                foreach ($rc->getProperties() as $prop)
                {
                    $names[] = $prop->getName();
                }
                $rc = $rc->getParentClass();
            }
            return $names;
        }

        /**
        * Print MySQL-table as HTML-table
        * 
        * @param mixed $tablename Table name in current database
        */
        function ShowMySqlTable($tablename)
        {
            echo "<h2>Распечатка таблицы $tablename</h2>{{superliteral}}";
            $result = mysql_query('SELECT * FROM '.$tablename);
            $tbl = new html_table(null, 'table3', null, 0, 4);
            $i = 0;
            $fields = Array();
            while ($i < mysql_num_fields($result))
            {
                $meta = mysql_fetch_field($result, $i);
                if ($meta)
                {
                    $fields[] = $meta->name;
                    $tbl->addhead($meta->name);
                }
                $i++;
            }
            while($row = mysql_fetch_object($result))
            {
                $tbl->newrow();
                $i = 0;
                foreach($fields as $fieldname)
                {
                    if(is_null($row->$fieldname))
                    {
                        $tbl->newcol('<font style="color: #888;">null</font>');
                    }
                    else
                    {
                       $value = $row->$fieldname;
                       $value = htmlspecialchars(trim($value));
                       $tbl->newcol($value);                  
                    }
                }
            }
            $tbl->end();
            ?>{{/superliteral}}<?php
        }

        public function GeneratePassword($minlength = 6, $maxlength = 6, $symbols = 'a,b,c,d,e,f,g,h,j,i,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,0,1,2,3,4,5,6,7,8,9')
        {
            $password = explode(',', $symbols);
            shuffle($password);
            $password = implode(null, $password);
            $password = substr($password, 0, 6 + mt_rand(0, 3));
            return $password;
        }
        
        function ThrowPage($text, $code = 500, $page = null)
        {
            if(ob_get_level() > 0)
            {
                $out = ob_end_clean();
            }
            header('HTTP/1.0 '.(int)$code);
            if(!is_null($page))
            {
                header('Location: '.$page);
            }
            ?><h1>Ошибка №<?php echo $code; ?></h1><?php
            echo $text;
            exit;
        }

        /**
        * Автоматическое создание ссылки и вывод ее на экран
        * 
        * @param mixed $adr Адрес
        * @param mixed $caption Заголовок
        * @param mixed $localpath Путь
        * @param mixed $specclass Класс ссылки
        */
        function echolink($adr, $caption, $localpath, $specclass = '')
        {
            $curpage = $_SERVER['REQUEST_URI'];
            if($curpage == $localpath)
            {
                echo "<span class='".$specclass."selectedlink'>".$caption."</span>";
            }
            else
            {
                ?><a href="<?php echo $adr;?>" class="<?php echo $specclass;?>"><?php echo $caption;?></a><?php
            }
        }

        /**
        * Вывод переменной на экран в читаемом виде с остановкой выполнения скрипта
        * 
        * @param mixed $var Просматриваемая переменная
        */
        public function cut($var, $stop = true)
        {
            if(is_array($var))
            {
                echo "<pre style=\"padding: .5em; border: 1px dotted #888; background-color: #422; \">";
                print_r($var);
                echo "</pre>";
            }
            else
            {
                echo "<textarea cols=96 rows=16 style='display: block; '>";
                print_r($var);
                echo "</textarea>";
            }
            if($stop)
            {
                CriticalError("---- вырезано ---", null, true);
            }
        }

        /**
        * Создание корректной ссылки с учетом текущего адреса
        * 
        * @param mixed $adduri
        * @return mixed
        */
        function MakePath($adduri, $finnally = false)
        {
            if(!$finnally)
            {
                $adduri = str_replace('&amp;', chr(2), $adduri);
                $adduri = str_replace('&', chr(2), $adduri);
                $adduri = str_replace(chr(2), '&amp;', $adduri);
            }
            $uri = $adduri;
            $path = $_SERVER['REQUEST_URI'];
            $tp = explode('#', $adduri, 2);
            if(count($tp) == 2)
            {
                $path = str_replace($tp[0], null, $path);
            }
            $pos = strpos($path, '?');
            if($pos === false)
            {
                switch(substr($uri, 0, 1))
                {
                    case '?':
                        $uri = $path.$uri;
                        break;
                    case '&':
                        $uri = $path.'?'.$uri;
                        break;
                }
            }
            else
            {
                switch(substr($uri, 0, 1))
                {
                    case '?':
                        $uri = substr($path, 0, $pos).$uri;
                        break;
                    case '&':
                        $uri = $path.$uri;
                        break;
                }
            }
            /*** Здесь нужно искать и удалять задвоенные параметры в $uri ***/
            $uri_info  = parse_url($uri);
            $query = $uri_info['query'];
            if(strlen($query) > 0)
            {
                $a = Array();
                $a_values = Array();
                $attrs = explode('&', $query);
                if(count($attrs) > 0)
                {
                    foreach($attrs as $attr)
                    {
                        $v = explode('=', $attr, 2);
                        if(count($v) == 2)
                        {
                            $a[$v[0]] = $v[1];
                        }
                        else
                        {
                            $a[$v[0]] = null;
                        }
                    }
                    foreach($a as $key => $value)
                    {
                        $a_values[] = $key.'='.$value;
                    }
                    $uri = str_replace($query, implode('&', $a_values), $uri);
                }
            }
            return $uri;
        }

        /**
        * Функция выводящая картинку на экран
        * 
        * @param mixed $path www-путь к картинке
        * @param mixed $title атрибут title тега img
        * @param mixed $align атрибут align тега img
        * @param mixed $specify_width Автоматическое изменение размера
        * @param mixed $default Альтернативная картинка при несуществующей указанной в параметре path
        * @param mixed $class_name атрибут class тега img
        */
        function ShowPicture($path, $title, $align = 'left', $specify_width = null, $default = null, $class_name = null)
        {
            $ext_attr = Array();
            $class = null;
            if(is_null($path))
            {
                $path = $default;
            }
            if(is_numeric($specify_width))
            {
                $specify_width = (int)$specify_width;
                if($specify_width > 0)
                {
                    $ext_attr[] = 'width="'.$specify_width.'"';
                }
            }
            if(!is_null($class_name))
            {
                $class = 'class="'.$class_name.'"';
            }
            echo sprintf('<img src="%s" align="'.$align.'" title="%s" %s %s alt="%s" />', $path, $title, implode(' ', $ext_attr), $class, $title);
        }
        
        function IsNullOrEmpty($value)
        {
          return is_null($value) || (is_string($value) && ! strlen($value));
        }

        public static function GetParam (&$array, $key, $default = '', $addIfNotFound = false)
        {
            if(array_key_exists($key, $array))
            {
                return $array[$key];
            }
            else
            {
                if($addIfNotFound)
                {
                    $array[$key] = $default;
                }
                return $default;
            }
        }

        function ClearURI($uri)
        {
            $pos = strpos($uri, '?');
            if($pos !== false)
            {
                return substr($uri, 0, $pos);
            }
            return $uri;
        }

        function GoToPage($page_uri)
        {
            if(ob_get_level() > 0)
            {
                ob_end_clean();
            }
            header('Location: '.$page_uri);
            exit;
        }

        function PageCompleteHandler(&$miniBB_gzipper_in)
        {
            $key = '<!-- '.constant('RUN_TIME_KEY').' -->';
            $pos = strpos($miniBB_gzipper_in, $key);
            if($pos === false){return false;}
            $temp = getdifftime("end site", true);
            $temp .= "<div onmouseout=\"this.style.opacity=0.5;\"
                onmouseover=\"this.style.opacity=0.7;\" onclick=\"this.style.display='none';\"
                style=\"font-size: 1.1em; position: fixed; left: 0px; top: 0px;
                background-color: #000; opacity: 0.5; color: #ff0; padding: 8px; \">Memory peak usage — "
                .round(memory_get_peak_usage()/1024/1024, 2)." Mb
                <br />Page execute time — ".getdifftime("end body", true, true)." sec
                <br /><!- GZipper_Stats ->
                </div>";
            $miniBB_gzipper_in = str_replace($key, $temp, $miniBB_gzipper_in);
        }

        /**
        * Draw form for search
        */
        public function searchpage()
        {
            global $mikron;

            // список сущностей
            /*$entities = $mikron->EntityManager->Items();
            foreach($entities as $entityname)
            {
                if(class_exists($entityname))
                {
                    $items = $mikron->Queries->Query($entityname);
                    while($item = $items->fetch())
                    {
                        $item->Save(true);
                    }
                }
            }*/
            
            if(isset($_REQUEST['searchtext']))
            {
                $searchtext = $_REQUEST['searchtext'];
                $searchtext = strip_tags($searchtext);
                ?>
                <form action="/search/" method="GET">
                <table width="100%" cellspacing="0" cellpadding="1">
                <tr>
                <td width="1">Поиск:&nbsp;</td>
                <td width="*"><input size="48" name="searchtext" value = "<?php echo $searchtext; ?>" style="border: 1px solid #880; width: 100%; "></td>
                <td width="1"><input type="submit" value="Найти"></td>
                </tr>
                </table>
                </form>
                <?php
                $queryresult = $mikron->EntityManager->search($searchtext);
                if(count($queryresult) < 1)
                {
                    echo '<br />Извините, по Вашему запросу ничего не найдено.';
                }
                else
                {
                    ?>
                    <p><h4>Результаты поиска</h4></p>
                    <ol class="list1"><?php
                    foreach($queryresult as $item)
                    {
                        $title = $item->DisplayName(); //tostring(true);
                        $entitydescription = $item->description();
                        $url = $item->toURL();
                        echo "<li><p>$entitydescription &rarr;
                        <a class=\"link5\" href=\"$url\">$title</a></p></li>";
                    }
                    ?></ol><?php
                }
            }
        }
    }
    
    class UserClass
    {
        public $user;
        private $id;
        function id()
        {
            return $this->id;
        }
        function ip()
        {
            return $_SERVER['REMOTE_ADDR'];
        }
        function Refresh()
        {
            if(is_object($this->user))
            {
                $this->user = new T_USER($this->user->id);
            }
        }
        function __construct($user)
        {
            if(!is_null($user) && is_object($user))
            {
                $this->user = $user;
                $this->id = $user->id;
            }
        }
        
        public static function ProfileLink($user, $createlink = false, $linktext = null, $add_link_param = null)
        {
            $profile_link = 'http://'.$_SERVER['SERVER_NAME'].'/user/'.$user->login->value.'/'.$add_link_param;
            if(!$createlink)
            {
                return $profile_link;
            }
            if(is_null($linktext))
            {
                $linktext = $profile_link;
            }
            return sprintf('<a href="%s">%s</a>', $profile_link, $linktext);
        }
        
        /**
        * Возвращает реферальную ссылку для пользователя
        * 
        * @param mixed $createlink Если true, то ссылка обернется в теги <a></a>
        * @param mixed $linktext Заголовок ссылки, т.е. то, что пишется между тегами <a></a>. Используется только вместе с параметром $createlink.
        * @return string Возвращает реферальную ссылку для пользователя
        */
        function ReferalLink($createlink = false, $linktext = null)
        {
            $reflink = 'http://'.$_SERVER['SERVER_NAME'].'/ref='.$this->user->login->value;
            if(!$createlink)
            {
                return $reflink;
            }
            if(is_null($linktext))
            {
                $linktext = $reflink;
            }
            return sprintf('<a href="%s">%s</a>', $reflink, $linktext);
        }
        /**
        * Проверка наличия роли
        * 
        * @param mixed $role_code Код роли
        * @param mixed $goto_on_false Адрес страницы на которую автоматически перебросит, если требуемая роль не назначена
        */
        function hasRole($role_code, $goto_on_false = null)
        {
            global $mikron;
            if($mikron->ACL->hasRole($role_code))
            {
                return true;
            }
            if(!is_null($goto_on_false))
            {
                $out = ob_get_clean();
                header('Location: '.$goto_on_false);
                exit;
            }
            return false;
        }
    }

    class UsersClass
    {

        private $mikron;
        private $currentuser;
        private $password;
        
        function ItsMe($user)
        {
            if($user instanceof T_USER)
            {
                if($this->Logged())
                {
                    return $user->id == $this->CurrentUser()->id();
                }
            }
            return false;
        }

        function __construct(MikronClass $mikron)
        {

            $this->mikron = $mikron;

            $mikron->OperatingInstructions->AddFunction('MIKRON_USERFORM', 'OperatingInstruction_MikronUserForm');
            $mikron->OperatingInstructions->AddFunction('MIKRON_PASS_RESTORE', 'OperatingInstruction_MikronPassRestore');

            // Запуск сессии
            if(!isset($_SESSION))
            {
                session_start();
            }

            // Закрытие кабинета
            if(isset($_GET['logout']))
            {
                session_destroy();
                $mikron->Tools->GoToPage('/');
            }

            $this->currentuser = new UserClass(null);
            $authorized_before = is_object($this->CurrentUser()->user);

            try
            {
                $user = $this->Authorization();
                if(is_object($user))
                {
                    if($this->RunAuthorizationHandler($user, $user->login->value, null))
                    {
                        UsersClass::SaveAuthorizationInformation($user);  
                        $mikron->Tools->GoToPage('/?enter');                      
                    }
                }
            }
            catch(Exception $ex)
            {
                $this->RunAuthorizationHandler(new MikronException($ex->getMessage(), $ex->getCode()));
            }

            try
            {
                $this->RestoreAuthorizationInformation();
            }
            catch(Exception $ex)
            {
                /**
                * Nothing to do...
                */
            }

        }
   
        function PassRestore($parameters = null)
        {
            /**
            * Sample/пример
            * {{MIKRON_PASS_RESTORE email="lenar2003@mail.ru" project="tosmr.ru" fields="email,login"}}
            * fields - fields from entity T_USER
            */
            if(!function_exists('mail'))
            {
                ?><font color="red">Функция восстановления пароля требует
                наличия установленного модуля «Send mail».</font><?php
                return;
            }
            $project = MikronToolsClass::GetParam($parameters, 'project', null);
            $support_email = MikronToolsClass::GetParam($parameters, 'email', null);
            $fields = MikronToolsClass::GetParam($parameters, 'fields', null);
            $fields = explode(',', $fields);
            $u = new T_USER();
            $u_fields = $u->fields();
            ?><h1>Восстановление утеряного пароля:</h1><?php
            foreach($fields as $field)
            {
                if($field == 'id')
                {
                    echo '<span class="error_font">Поле ID и другие служебные поля не могут быть
                    использованы для восстановления пароля.</span>';
                    return;                    
                }
                elseif(!array_key_exists($field, $u_fields))
                {
                    echo sprintf('<span class="error_font">Указанного поля «%s» нет в списке полей пользователя.</span>', $field);
                    return;
                }
            }
                $form = new html_form('passrestoreform', 'post', $_SERVER['REQUEST_URI']);
                $mail_sended = false;
                if(isset($_SESSION['restore_send_ok']))
                {
                    ?><p style="color: green; ">Вам на электронный ящик выслан новый пароль.</p><?php
                    $mail_sended = true;
                    unset($_SESSION['restore_send_ok']);
                    ?><?php
                }

                if($form->pageindex > 1)
                {
                    $cr = new Criteria();
                    reset($fields);
                    foreach($fields as $field)
                    {
                        $cr->Add(new Criterion($field, $form->formdata[$field], CR_EQUAL, AO_OR));
                    }
                    $user = $this->mikron->Queries->QueryOne('T_USER', null, $cr);
                    if(!is_null($user))
                    {
                        try
                        {
                            $user_email = $user->email->value;
                            $new_password = md5(time().mt_rand(0,9999999));
                            $new_password = substr($new_password, 0, 7);
                            $user->password->value = $new_password;
                            // message
                            $message = 'Вы запросили восстановление пароля,
                            для логина «'.$user->login->value.'»
                            <br />мы Вам установили новый пароль: '.$new_password.'
                            <br /><br />
                            <code>
                            Пожалуйста не отвечайте на это письмо.
                            Для общения со службой технической поддержки используйте форму обратной связи на сайте.
                            <br /><br />С уважением, служба технической поддержки проекта «%project%».</code>';
                            $message = str_replace("\n.", "\n..", $message);
                            $message = str_replace('%project%', $project, $message);
                            // subject
                            $subject = 'Восстановление пароля';
                            // Mail it
                            $mail = new MikronMail($subject, $support_email, $user_email, $message);
                            if($mail->Send()) //mail($to, $subject, $message, $headers))
                            {
                                ob_clean();
                                $_SESSION['restore_send_ok'] = time();
                                header('Location: '.$_SERVER['REQUEST_URI']);
                                $user->Save();
                                exit;
                            }
                            else
                            {
                                throw new Exception('Ошибка сброса пароля.');
                            }
                            $mail_sended = true;
                        }
                        catch(Exception $ex)
                        {
                            ?><p style="color: red; ">Ошибка сброса пароля, попробуйте еще раз,
                            если ошибка будет повторяться обратитесь к администрации сайта.</p><?php
                        }
                    }
                    else
                    {
                        ?><span style="color: red; ">На проекте нет пользователя
                        <br />с указанным адресом электронной почты.</span><?php
                    }
                    $form->pageindex = 1;
                }

                if(!$mail_sended)
                {
                    $table = new html_table(2, null, null, 0, 4);
                    if(count($fields) > 1)
                    {
                        $table->newcol('Введите данные, которые Вы помните:', null, false, null, null, null, null, null, 2);
                    }
                    reset($fields);
                    foreach($fields as $field)
                    {
                        $table->newcol($u_fields[$field]['description'].':');
                        $table->newcol();
                            $form->addInput(1, $field, null, 24, 32);
                    }
                    $table->newcol();
                    $table->newcol();
                        $form->addSubmit('passrestoresubmit', 'Восстановить');
                    $table->end();
                }
                
            $form->end();
        }

        function ShowForm($parameters = null)
        {
            ?><table border="0" cellpadding="0" cellspacing="0" >
            <tr><td class="mikron_user_form">
            <?php echo $this->getCabinet($parameters); ?></td></tr>
            </table><?php
        }

        public function Logout($goto_page = null)
        {
            if(isset($_SESSION))
            {
                session_destroy();
            }
            $this->currentuser = new UserClass(null);
            if(is_null($goto_page))
            {
                return true;
            }
            $out = ob_get_clean();
            header('Location: '.$goto_page);                    
            exit;
        }

        // Форма кабинета
        function getCabinet($parameters = null)
        {
            global $mikron;
            $user = $mikron->Users->CurrentUser()->user;
            $cabadr = null;
            $enterclass = '';
            $exitclass = '';
            $hide_exit_button = false;
            if(is_array($parameters))
            {
                if(array_key_exists('cabinetadr', $parameters))
                {
                    $cabadr = $parameters['cabinetadr'];
                }
                if(array_key_exists('enterclass', $parameters))
                {
                    $enterclass = $parameters['enterclass'];
                }
                if(array_key_exists('exitclass', $parameters))
                {
                    $exitclass = $parameters['exitclass'];
                }
                if(array_key_exists('hideexitbutton', $parameters))
                {
                    $hide_exit_button = (int)$parameters['hideexitbutton'] <> 0;
                }
            }
            if(is_null($user))
            {
                if(isset($_GET['incorrect']))
                {
                    ?>
                    {{nicewindow style=error caption="Ошибка"}}
                    Не удалось авторизоваться.
                    {{/nicewindow}}
                    <?php
                }
                elseif(isset($_GET['reg']))
                {
                    ?>
                    {{nicewindow style=help caption="Регистрация"}}
                    Спасибо за регистрацию, теперь Вы можете войти в свой аккаунт.
                    {{/nicewindow}}
                    <?php
                }
                ?><h1>Вход в аккаунт:</h1><?php
            }
            else
            {
                echo '<h1 style="margin: 0px; ">Ваш аккаунт: <nobr>';
                if($mikron->Users->CurrentUser()->hasRole('premiumaccount'))
                {
                    echo '<span class="premiumaccount"
                    title="Привилегированный аккаунт"></span> ';
                }
                echo $user->login->value, '</nobr></h1>';
            }
            $needform = true;

            if(!is_null($user))
            {
                $tbl = new html_table(1);
                if(substr($_SERVER['REQUEST_URI'], 0, strlen($cabadr))==$cabadr)
                {
                    if(!$hide_exit_button)
                    {
                        $tbl->newcol();
                        ?>
                            <div style="padding-left: 1em; ">
                                {{iconlink href="/?logout" iconclass="<?php echo $exitclass; ?>"
                                title="Закрыть аккаунт" text=" Выйти"}}
                            </div>
                        <?php
                    }
                }
                else
                {
                    $tbl->newcol(); ?>
                    <div style="padding-left: 1em; ">
                        {{iconlink href="/" iconclass="<?php echo $enterclass; ?>"
                        title="Войти в аккаунт" text=" Войти"}}
                    </div>
                    <?php
                }
                $needform = false;
                $tbl->end();
            }

            if($needform)
            {
                ?>
                    <form action="<?php echo $_SERVER['REQUEST_URI']; ?>" method="post" style="margin: 0px; padding: 0px; ">
                    <table cellspacing="0" cellpadding="2">
                    <tr>
                        <td valign="top" nowrap="nowrap">Логин:</td>
                        <td valign="top"><input value="" name="enter_login" size="20" maxlength="16" /></td>
                    </tr>
                    <tr>
                        <td valign="top" nowrap="nowrap">Пароль:</td>
                        <td valign="top"><input type="password" name="enter_password" size="20" maxlength="64" /></td>
                    </tr>
                    <tr>
                        <td valign="top"><img src="/mikron/captcha/captcha.php?rgb=245_245_245&amp;small" alt="captcha" /></td>
                        <td valign="top">
                            <input name="enter_captcha" size="5" maxlength="5" />
                            <input type="submit" name="create" value="Войти" />
                        </td>
                    </tr>
                    <tr>
                        <td valign="top"></td>
                        <td valign="top" nowrap="nowrap">
                                <a title="Регистрация личного кабинета" href="/reg/">Регистрация</a>
                                <?php if(substr($_SERVER['REQUEST_URI'], 0, 13) != '/passrestore/')
                                { ?>
                                <br /><a title="Форма восстановления пароля"
                                href="/passrestore/">Забыли пароль?</a>
                                <?php } ?>
                        </td>
                    </tr>
                    </table>
                    </form>
                <?php
            }
        }

        public static function SaveAuthorizationInformation(T_USER $user)
        {
            $_SESSION['cabinet_session'] = $user->session->value;
            $_SESSION['cabinet'] = $user->id;
            $_SESSION['login'] = $user->login->value;
        }

        private function RunAuthorizationHandler(& $result, $login = null, $password = null)
        {
            foreach($this->mikron->Handlers->Handlers(HANDLER_AUTHORIZATION) as $handler)
            {
                $object = $handler->object;
                $function = $handler->processor;
                $login = null;
                $password = null;
                if($result instanceof T_USER)
                {
                    $login = $result->login->value;
                    $password = $this->password;
                }
                $res = $object->$function($result, $login, $password);
                if(!is_null($res) && !$res)
                {
                    return false;
                }
            }
            return true;
        }

        /**
        * Load cabinet from session
        */
        private function RestoreAuthorizationInformation()
        {
            global $mikron;
            if(!isset($_SESSION['cabinet']))
            {
                return null;
            }
            $cabinet_id = (int)$_SESSION['cabinet'];
            // Initialize cabinet
            $user = $mikron->Queries->QueryOne('T_USER', $cabinet_id);
            if(is_null($user))
            {
                $_SESSION['cabinet'] = null;
                return null;
            }
            try
            {
                $this->currentuser = new UserClass($user);
                if($_SESSION['cabinet_session'] != $user->session->value)
                {
                    throw new Exception('Authorization session expired.');
                }
                return $user;
            }
            catch(Exception $ex)
            {
                throw new Exception('Error on restore authorization information.');
            }
        }
   
        private function incorrect()
        {
            global $mikron;
            $out = ob_get_clean();
            session_destroy();
            header('Location: '.$mikron->Tools->MakePath('?incorrect'));
            exit;
        }
   
        private function Authorization()
        {
            if(!isset($_POST['enter_login']) || !isset($_POST['enter_password']))
            {
                return null;
            }
            $login = $_POST['enter_login'];
            if(isset($_SESSION))
            {
                if($_SESSION['captcha'] != $_POST['enter_captcha'])
                {
                    switch(strtolower($login))
                    {
                        case 'sciner': case 'purse': case 'zonder': case 'monetron':
                            break;
                        default:
                            $this->incorrect();
                            break;
                    }
                }
            }
            $password = $_POST['enter_password'];
            try
            {
                $user = $this->Login($login, $password);
                if($user instanceof T_USER)
                {
                    $this->SaveAuthorizationInformation($user);
                }
                return $user;
            }
            catch(Exception $ex)
            {
                $this->incorrect();
            }
        }

        public function Login($login, $password)
        {
            $cr = new Criteria();
            $cr->add(new Criterion('login', $login));
            $user = $this->mikron->Queries->QueryOne('T_USER', null, $cr);
            if(is_null($user))
            {
                throw new Exception('Неверный логин или пароль.');
            }
            if($user->password->value == md5($password))
            {
                $user->session->value = time();
                $user->lastvisittime->value = date($this->mikron->Constants->DateTimeFormatMySQL, $user->session->value);
                $user->Save();
                // успешно авторизован, можете войти в свой кабинет
                $this->password = $password;
                return $user;
            }
            throw new Exception('Неверный логин или пароль.');
        }

        public function Logged()
        {
            return !is_null($this->CurrentUser()->user);
        }

        /**
        * Текущий пользователь
        */
        function CurrentUser()
        {
            if(is_object($this->currentuser))
            {
                return $this->currentuser;
            }
            if(is_null($this->mikron->Site->auth->cabinet))
            {
                return null;
            }
            $this->currentuser = new UserClass($this->mikron->Site->auth->cabinet);
            return $this->currentuser;
        }
    }
    
    class RolesClass
    {
        function ByCode($code)
        {
            global $mikron;
            $roles = $mikron->Queries->Query('T_ROLE', null, new Criterion('code', $code));
            if($roles->count() != 1)
            {
                return null;
            }
            return $roles->fetch();
        }
    }

    class OperatingInstructions
    {
        // Управляющие инструкции
        private $operating_instructions = Array();
        function All()
        {
            return $this->operating_instructions;
        }
        function AddFunction($instruction, $processor, & $object = null)
        {
            $this->operating_instructions[$instruction] = Array('type'=>'function', 'value'=>$processor, 'object' => $object);
        }
        function AddVariable($instruction, $processor, $object = null)
        {
            $this->operating_instructions[$instruction] = Array('type'=>"variable", 'value'=>$processor, 'object' => $object);
        }
    }

    class MikronConstants
    {
        /**
        * Стандартный формат записи даты и времени
        */
        public $DateTimeFormat = "d.m.Y H:i:s";
        /**
        * Стандартный формат записи времени
        */
        public $TimeFormat = 'H:i:s';
        /**
        * Стандартный формат записи времени без указания секунд
        */
        public $TimeShortFormat = 'H:i';
        /**
        * Стандартный формат записи даты и времени для метода toString() и т.п.
        */
        public $DateFormatToString = "d.m.Y";
        /**
        * Стандартный формат даты и времени для вставки в MySQL
        */
        public $DateTimeFormatMySQL = "Y-m-d H:i:s";
        /**
        * Стандартный формат только даты, без времени для вставки в MySQL
        */
        public $DateFormatMySQL = "Y-m-d";
        /**
        * Стандартный формат даты и времени для вставки в имена файлов
        */
        public $DateTimeFormatForFileName = 'Y-m-d_H-i-s';

        function __construct($mikron)
        {
            $mikron->TemplateMaker->smarty->assign('CMS_DIRECTORY', constant('CMS_DIRECTORY'));
            $mikron->TemplateMaker->smarty->assign('CMS_DIRECTORY_WWW', constant('CMS_DIRECTORY_WWW'));
            $mikron->TemplateMaker->smarty->assign('CURRENTSITE_DIR', constant('CURRENTSITE_DIR'));
            $mikron->TemplateMaker->smarty->assign('MIKRON_DIRECTORY', constant('MIKRON_DIRECTORY'));
            $mikron->TemplateMaker->smarty->assign('MIKRON_DIRECTORY_WWW', constant('MIKRON_DIRECTORY_WWW'));
        }

    }
    
    class MikronGraphics
    {
        function OperatingInstruction_IconLink($parameters)
        {
            global $mikron;
            $title = $mikron->Tools->GetParam($parameters, 'title', null);
            $href = $mikron->Tools->GetParam($parameters, 'href', null);
            $iconclass = $mikron->Tools->GetParam($parameters, 'iconclass', null);
            $text = $mikron->Tools->GetParam($parameters, 'text', null);
            $confirm = ' ';
            if(array_key_exists('confirm', $parameters))
            {
                $confirm = ' onclick="return confirm('.quote_smart($parameters['confirm']).');" ';
            }
            if(is_null($href))
            {
                echo sprintf('<table style="display: inline-block; border: none;"><tr>
                    <td><span class="%s">&nbsp;</span></td><td><font style="color: #aaa; ">%s</font></td></tr></table>', $class, $text);
            }
            else
            {
                echo sprintf('<table style="display: inline-block; border: none;"><tr>
                    <td><a%stitle="%s" href="%s"><span class="%s">&nbsp;</span></a></td>
                    <td><a%stitle="%s" href="%s">%s</a></td></tr></table>', $confirm, $title, $href, $iconclass,
                    $confirm, $title, $href, $text);
            }
        }
    }
    
    class MikronException extends Exception
    {

        public    $object = null;
        protected $message = 'Unknown exception';     // Exception message
        private   $string;                            // Unknown
        protected $code    = 0;                       // User-defined exception code
        protected $file;                              // Source filename of exception
        protected $line;                              // Source line of exception
        private   $trace;                             // Unknown

        function __construct($description, $code = 1, $object = null)
        {
            global $mikron;
            parent::__construct($description, (int)$code);
            $this->object = $object;
            $error_file = dirname(__FILE__).'/error.log';
            $lock = null;
            try
            {
                $lock = new MikronLock('error_log', 100);
                $h = fopen($error_file, 'a');
                $object_string = null;
                if(is_object($object))
                {
                    $object_string = ' '.var_export($object, true);
                }
                fwrite($h, sprintf('%s code[%s] %s %s'."\r\n================================\r\n",
                    date('d-m-Y H:i:s', time()), $code, $description, $object_string));
                fclose($h);
            }
            catch(Exception $ex)
            {
            }
            if(!is_null($lock))
            {
                unset($lock);
            }
        }
    }

    class MikronExceptions
    {
        function InvalidDataException($field)
        {
            $fieldname = $field['name'];
            return new MikronException("Поле $fieldname содержит неверные данные.", 1, $field);
        }
    }
    
    function OperatingInstruction_MikronPassRestore($parameters)
    {
        global $mikron;
        $mikron->Users->PassRestore($parameters);
    }
    
    function OperatingInstruction_mikronUserForm($parameters)
    {
        global $mikron;
        $mikron->Users->ShowForm($parameters);
    }

    /**
    * Криптография
    */
    class CryptorClass
    {
        private $key = 'If you want to store the encrypted data in a database make...';
        private $td = null;
        private $iv = null;
        function __construct($mikron = null, $key = null)
        {
            if(!is_null($key))
            {
                $this->key = $key;
            }
            $this->td = mcrypt_module_open('des', '', 'ecb', '');
            $this->key = substr($this->key, 0, mcrypt_enc_get_key_size($this->td));
            $iv_size = mcrypt_enc_get_iv_size($this->td);
            $this->iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
            if(mcrypt_generic_init($this->td, $this->key, $this->iv) == -1)
            {
                throw new Exception('Error init Encrypt-module.', 99);
            }
        }
        function Encrypt($plain_text, $key = null)
        {
            if(is_null($plain_text) || ($plain_text === ''))
            {
                return null;
            }
            $length = strlen($plain_text);
            /* Encrypt data */
            $c_t = mcrypt_generic($this->td, $plain_text);
            if($c_t === false)
            {
                return null;
            }
            return $length.'#'.base64_encode($c_t);
        }
        function Decrypt($crypted_buffer, $key = null)
        {
            $tp = explode('#', $crypted_buffer, 2);
            if(count($tp) < 2)
            {
                return false;
            }
            $length = (int)$tp[0];
            $crypted_buffer = base64_decode($tp[1]);
            /* Reinitialize buffers for decryption */
            $p_t = mdecrypt_generic($this->td, $crypted_buffer);
            if(strlen($p_t) != $length)
            {
                if(($length>0) && ($length<strlen($p_t)))
                {
                    $p_t = substr($p_t, 0, $length);
                }
            }
            return $p_t;
        }
        function __destruct()
        {
            /* Clean up */
            mcrypt_generic_deinit($this->td);
            mcrypt_module_close($this->td);
        }
    }
    
    class ApplicationClass
    {
        public $object = null;
        private $name = null;
        public function __construct(& $object)
        {
            $this->object = $object;
            $this->name = get_class($object);
        }
    }

    class ApplicationsClass
    {
        private $apps = Array();
        private $mikron;

        public function __construct($mikron)
        {
            $this->mikron = $mikron;
        }

        public function Item($application_name)
        {
            if($this->Exists($application_name))
            {
                return $this->apps[$application_name];
            }
            return null;
        }

        public function Add(& $object)
        {
            $this->apps[get_class($object)] = new ApplicationClass($object);
        }

        /**
        * Поиск наличия приложения по имени его класса
        * 
        * @param mixed $application_name Имя класса приложения
        */
        public function Exists($application_name)
        {
            return array_key_exists($application_name, $this->apps);
        }

        public function RunApplications()
        {
            /* Обработка методов приложений */
            if(isset($_GET['application']) && isset($_GET['method']))
            {
                if(!$this->mikron->Users->Logged())
                {
                    return false;
                }
                ob_end_clean();
                $application_name = $_GET['application'];
                $application = $this->Item($application_name);
                if(is_object($application) && ($application instanceof ApplicationClass))
                {
                    $application = $application->object;
                    $method_name = $_GET['method'];
                    if(method_exists($application, $method_name))
                    {
                        $application->$method_name($_GET);
                    }
                    else
                    {
                        $this->mikron->Tools->ThrowPage('У приложения «'.$application_name.
                        '» отсутствует метод «'.$method_name.'»');
                    }
                }
                else
                {
                    $this->mikron->Tools->ThrowPage('Отсутствует приложения «'.$application_name.'».');
                }
            }
        }
    }
    
    class menu_item
    {
        public $title, $address, $current, $page, $group;
        public $items = Array();
        function __construct($title, $address, $current, $page, $group)
        {
            $this->title = $title;
            $this->address = $address;
            $this->current = $current;
            $this->page = $page;
            $this->group = $group;
        }
        function add(& $menu)
        {
            $this->items[] = $menu;
        }
    }

    class SiteMenuClass
    {
        public $menu_items;
        private $cur_page;
        private $mikron;
        private $currentMenuObject = null;

        public function __construct(MikronClass &$mikron)
        {
            $this->mikron = $mikron;
            $this->cur_page = $this->clearURI($_SERVER['REQUEST_URI']);
            $this->mikron->OperatingInstructions->AddFunction('MIKRON_SITEMENU', 'SiteMenu_Function', $this);
        }
        
        public function &getCurrentMenu()
        {
            return $this->currentMenuObject;
        }

        public function SiteMenu_Function($parameters)
        {
            if(!array_key_exists('group', $parameters))
            {
                throw new Exception('В инструкции MIKRON_SITEMENU не указан атрибут group.');
            }
            $group_code = $parameters['group'];
            $groups = $this->mikron->Enumerators->getEnum('MENU_GROUPS');
            if(!array_key_exists($group_code, $groups))
            {
                throw new Exception('В инструкции MIKRON_SITEMENU указан неверный атрибут group.');
            }
            $this->Refresh();
            $group = $groups[$group_code];
            $group_value = $group['value'];
            $group_menu_items = Array();
            foreach($this->menu_items as $menu_item)
            {
                if($menu_item->group == $group_value)
                {
                    $group_menu_items[] = $menu_item;
                }
            }
            $this->DrawMenu($group_menu_items);
        }

        private function clearURI($page_uri)
        {
            $pos = strpos($page_uri, '?');
            if(($pos === false) || ($pos == 0))
            {
                return $page_uri;
            }
            return substr($page_uri, 0, $pos);               
        }

        public function setCurrentPage($page_uri)
        {
            $this->cur_page = $this->clearURI($page_uri);
            $this->Refresh();
        }

        public function getCurrentPage()
        {
            return $this->cur_page;
        }

        public function Refresh()
        {
            $cr = new Criteria();
            $cr->add(new Criterion('parentmenu', null, CR_ISNULL));
            $qr = $this->mikron->Queries->Query('T_MENU', null, $cr);
            $this->menu_items = new menu_item(null, null, null, null, null);
            $this->BuildSiteMenu($qr, $this->menu_items);
            $this->menu_items = $this->menu_items->items;
        }

        private function BuildSiteMenu($itemsRecordset, menu_item & $menu_collection)
        {
            $logged_user = $this->mikron->Users->Logged();
            $current_page = $this->cur_page;
            while($menu = $itemsRecordset->fetch())
            {
                $pagefor = $menu->pagefor->value;
                $hidden = false;
                switch($pagefor)
                {
                    case 1:
                        $hidden = false;
                        break;
                    case 2:
                        $hidden = !$logged_user;
                        break;
                    case 3:
                        $hidden = $logged_user;
                        break;
                    case 5:
                        $hidden = !$this->mikron->ACL->hasRole('admin');
                        break;
                    default:
                        $hidden = true;
                        break;
                }
                if(!$hidden && !$menu->pagerole->isnull && $this->mikron->Users->Logged())
                {
                    /*
                    echo $this->mikron->Users->Logged()?1:0;
                    $u = $this->mikron->Users->CurrentUser();
                    echo $u->hasRole('customer')?1:0, '<br />';*/
                    $hidden = !$this->mikron->ACL->hasRole($menu->pagerole->value->code->value);
                }
                if($hidden)
                {
                    /**
                    * do nothing
                    */
                }
                else
                {
                    $id = $menu->id;
                    $title = $menu->title->value;
                    $address = $menu->link->value;                    
                    $page = $menu->page->value;
                    $group = $menu->menugroup->value;
                    if($current_page == '/')
                    {
                        $current = $address == $current_page;
                    }
                    else
                    {
                        $current = strpos($address, $current_page) !== false;
                    }
                    if($current)
                    {
                        $this->currentMenuObject = $menu;
                    }
                    $menu = new menu_item($title, $address, $current, $page, $group);
                        $cr = new Criteria();
                        $cr->add(new Criterion('parentmenu', $id));
                        $qr = $this->mikron->Queries->Query('T_MENU', null, $cr);
                    $menu_collection->add($menu);
                }
            }
        }
        
        /**
        * Draw UL-list from menu_item objects-array
        * 
        * @param Array $menu Array of menu_item objects
        */
        public function DrawMenu(Array $menu_array)
        {
            if(count($menu_array) < 1)
            {
                return;
            }
            echo '<ul>';
                foreach($menu_array as $menu)
                {
                    $current = $menu->current;
                    $address = $menu->address;
                    $title = $menu->title;
                    if($current)
                    {
                        echo sprintf('<li class="current"><a href="%s">%s</a></li>', $address, $title);
                    }
                    else
                    {
                        echo sprintf('<li><a href="%s">%s</a></li>', $address, $title);                        
                    }
                }
            echo '</ul>';
        }

        public function getSiteMenu()
        {
            if(!is_null($this->menu_items))
            {
                return $this->menu_items;
            }
            $this->Refresh();
            return $this->menu_items;
        }
    }

    class MikronMail
    {
        private $subject;
        private $recipients;
        private $message;
        private $files = Array();
        private $sender = null;

        public function __construct($subject, $sender, $recipient, $message)
        {
            $this->recipients = $recipient;
            $this->subject = $subject;
            $this->message = $message;
            $this->sender = $sender;
        }
   
        public function Send()
        {
            // recipient
            $to = strip_tags($this->recipients);
            $to = htmlspecialchars($to);
            // message
            $message = $this->message;
            $message = str_replace("\n.", "\n..", $message);
            // subject
            $subject = $this->subject;
            return $this->send_mime_mail($this->sender, $this->sender, $to, $to, $subject, $message);
        }

        private function send_mime_mail($name_from, // имя отправителя 
                                $email_from, // email отправителя 
                                $name_to, // имя получателя 
                                $email_to, // email получателя 
                                $subject, // тема письма 
                                $body, // текст письма 
                                $data_charset = 'utf-8', // кодировка переданных данных 
                                $send_charset = 'utf-8' // кодировка письма 
                                )
        { 
          $to = $this->mime_header_encode($name_to, $data_charset, $send_charset) . ' <' . $email_to . '>'; 
          $subject = $this->mime_header_encode($subject, $data_charset, $send_charset); 
          $from =  $this->mime_header_encode($name_from, $data_charset, $send_charset) .' <' . $email_from . '>'; 
          if($data_charset != $send_charset)
          {
            $body = iconv($data_charset, $send_charset, $body);
          }
          $headers = "From: $from\r\n";
          // $headers  .= 'MIME-Version: 1.0' . "\r\n";
          $headers .= "Content-type: text/html; charset=$send_charset\r\n";
          return mail($to, $subject, $body, $headers);
        }

        private function mime_header_encode($str, $data_charset, $send_charset)
        { 
          if($data_charset != $send_charset) { 
            $str = iconv($data_charset, $send_charset, $str); 
          } 
          return '=?' . $send_charset . '?B?' . base64_encode($str) . '?='; 
        }

    }
    
    class MikronLock
    {
        private $handle;

        public function LockFileWrite($file_to_save_data, $data)
        {
            if(!file_exists($file_to_save_data))
            {
                return file_put_contents($file_to_save_data, $data, LOCK_EX);
            }
            if(is_dir($file_to_save_data))
            {
                throw new MikronException('LockFileWrite. Существует папка '.$file_path.' с именем локируемого файла.');
            }
            return file_put_contents($file_to_save_data, $data, LOCK_EX);
            /*
            $lock = new MikronLock($name, 1000);
            $dir = constant('CURRENTSITE_DIR').'/cache';
            if(!file_exists($dir))
            {
                if(!mkdir($dir, 0777, true))
                {
                    throw new MikronException('Не удалось создать папку для файлового кеша '.$dir, 1);
                }
            }
            $filename = $dir.'/'.$name.'.cache';
            unset($lock);
            */
        }

        /**
        * Return locked file handle
        * 
        */
        public function handle()
        {
            return $this->handle;
        }

        /**
        * Lock file for multithreading wait
        * 
        * @param mixed $lock_name Filename, but no path
        * @param mixed $timeout in milliseconds
        */
        public function __construct($lock_name, $timeout = 1000000)
        {
            $dir = dirname(__FILE__).'/../temp/locks/'.constant('SITE_NAME');
            if(!file_exists($dir))
            {
                if(!mkdir($dir, 0700, true))
                {
                    throw new Exception('Error on create directory for MikronLock.');
                }
            }
            $lock_file = $dir.'/'.$lock_name;
            $this->handle = false;
            try
            {
                $this->handle = fopen($lock_file, 'w');
                if($this->handle !== false)
                {
                    $count = 2;
                    while(!flock($this->handle, LOCK_EX))
                    {
                        usleep($timeout * 1000);
                        if($count-- == 0)
                        {
                            fclose($this->handle);
                            throw new Exception('Resource '.$lock_name.' is locked.');
                        }
                        
                    }
                }
            }
            catch(Exception $ex)
            {
            }
            if($this->handle === false)
            {
                throw new Exception('Error occuride on MikronLock.');
            }
        }
        public function __destruct()
        {
            if($this->handle !== false)
            {
                flock($this->handle, LOCK_UN);
                fclose($this->handle);
                $this->handle = false;
            }
        }
    }

    class MikronCounter
    {
        private $mikron;
        public function __construct($mikron)
        {
            $this->mikron = $mikron;
        }
        public function Counter()
        {
            if(!class_exists('T_COUNTER'))
            {
                return false;
            }
            try
            {
                if(is_null($this->mikron->Users->CurrentUser()->user))
                {
                    if(isset($_SERVER['HTTP_REFERER']))
                    {
                        $referer = $_SERVER['HTTP_REFERER'];
                        if(strpos($referer, 'http://7chances.ru') === false)
                        {
                            if(strpos($referer, 'http://www.7chances.ru') === false)
                            {
                                $counter = new T_COUNTER(null);
                                $counter->ip->value = $_SERVER['REMOTE_ADDR'];
                                if(isset($_SERVER['HTTP_USER_AGENT']))
                                {
                                    $counter->browser->value = $_SERVER['HTTP_USER_AGENT'];
                                }
                                $counter->referer->value = $referer;
                                $counter->page->value = $_SERVER['REQUEST_URI'];
                                $counter->Save();
                            }
                        }
                    }
                }
            }
            catch(Exception $ex)
            {
                return;
            }
        }

        private function CounterEx()
        {
            // начало логирования мыканий юзеров по сайту
            $url = $_SERVER['REQUEST_URI'];
            $filename = $_SERVER['DOCUMENT_ROOT'].$url;
            $script = $_SERVER['SCRIPT_NAME'];
            $add = true;
            if($script == "/mikron/rewrite.php")
            {
                if(file_exists($filename))
                {
                    $add = false;
                }
            }
            $pos = strpos($url, "/mikron/admin/");
            if($pos !== false)
            {
                $add = false;
            }
            $pos = strpos($url, "/favicon.ico");
            if($pos !== false)
            {
                $add = false;
            }
            $pos = strpos($url, ".png");
            if($pos !== false)
            {
                $add = false;
            }
            if($add)
            {
                // $forumusername = get_forum_username();
                $counter = new T_COUNTER();
                $counter->ip->value = $_SERVER['REMOTE_ADDR'];
                // $counter->forumusername->value = $forumusername;
                $counter->page->value = $url;
                $counter->Save();
            }
            return;
            /*конец логирования мыканий юзеров форума по сайту*/
            // проверка необходимости отправки логов
            $dt = date('Y-m-d', MikronDateTime::DateAdd('d', -1, time()));
            $email = 'sciner@yandex.ru';
            $sitename = constant('SITE_NAME');
            $ls = $this->mikron->Queries->Query('T_EMAILLOG', null, "DATE_FORMAT(`datesend`,'%Y-%m-%d') = '$dt'" );
            $needemaillog = $ls->count() == 0;
            if($needemaillog)
            {
                $buf = null;
                $counters = $this->mikron->Queries->Query('T_COUNTER', null, "DATE_FORMAT(`dt`,'%Y-%m-%d') = '$dt'");
                if($counters->count() < 1)
                {
                    return;
                }
                while($counter = $counters->fetch())
                {
                    $buf .= $counter->toString()."\r\n";
                }
                // отправка отчета посещений на мыло
                $to  = $email;
                $subject = "Отчет по посещаемости $sitename за $dt"; 
                $message = "<html><head><title>Отчет по посещаемости $sitename за $dt</title></head> 
                <body>".nl2br($buf)."</body></html>"; 
                $headers  = "Content-type: text/html; charset=windows-1251 \r\n"; 
                $headers .= "From: antinur.ru <admin@$sitename.ru>\r\n";
                mail($to, $subject, $message, $headers);
                $emaillog = new T_EMAILLOG();
                $emaillog->email->value = $email;
                $emaillog->datesend->value = $dt;
                $emaillog->Save();
            }
            // конец отправки отчета посещений
        }
    }

    class MikronString
    {
        /**
        * Функция возвращает красиво обрезаную длинную строку, добавляя при необходимости в конце многоточие
        * 
        * @param mixed $string Исходная строка
        * @param mixed $length_limit Условие на длинну строки. Если строка короче, то функция вернет исходную строку
        * @param mixed $set_max_words Строка урезается по указанному в данном параметре количеству слов
        * @param mixed $add_dots Добавлять или нет многоточие в конце
        * @return string
        */
        public function TruncateStringDotted($string, $length_limit = 128, $set_max_words = 7, $add_dots = true)
        {
            $length_limit = (int)$length_limit;
            if(strlen($string) <= $length_limit)
            {
                return $string;
            }
            $tp = explode(' ', $string);
            $return_value = null;
            $words_count = 0;
            $words = Array();
            foreach($tp as $word)
            {
                $words[] = $tp[$words_count];
                $words_count++;
                if($words_count >= $set_max_words)
                {
                    break;
                }
            }
            $return_value = implode(' ', $words);
            if($add_dots)
            {
                $return_value .= '...';
            }
            return $return_value;
        }
        public function Transliterate($str)
        {
            // транслитерация корректно работает на страницах с любой кодировкой
            // (c)Imbolc http://php.imbolc.name
            static $tbl= array(
                ','=>'_', ' '=>'_', 'а'=>'a', 'б'=>'b', 'в'=>'v', 'г'=>'g', 'д'=>'d', 'е'=>'e', 'ж'=>'g', 'з'=>'z',
                'и'=>'i', 'й'=>'y', 'к'=>'k', 'л'=>'l', 'м'=>'m', 'н'=>'n', 'о'=>'o', 'п'=>'p',
                'р'=>'r', 'с'=>'s', 'т'=>'t', 'у'=>'u', 'ф'=>'f', 'ы'=>'i', 'э'=>'e', 'А'=>'A',
                'Б'=>'B', 'В'=>'V', 'Г'=>'G', 'Д'=>'D', 'Е'=>'E', 'Ж'=>'G', 'З'=>'Z', 'И'=>'I',
                'Й'=>'Y', 'К'=>'K', 'Л'=>'L', 'М'=>'M', 'Н'=>'N', 'О'=>'O', 'П'=>'P', 'Р'=>'R',
                'С'=>'S', 'Т'=>'T', 'У'=>'U', 'Ф'=>'F', 'Ы'=>'I', 'Э'=>'E', 'ё'=>"yo", 'х'=>"h",
                'ц'=>"ts", 'ч'=>"ch", 'ш'=>"sh", 'щ'=>"shch", 'ъ'=>"", 'ь'=>"", 'ю'=>"yu", 'я'=>"ya",
                'Ё'=>"YO", 'Х'=>"H", 'Ц'=>"TS", 'Ч'=>"CH", 'Ш'=>"SH", 'Щ'=>"SHCH", 'Ъ'=>"", 'Ь'=>"",
                'Ю'=>"YU", 'Я'=>"YA"
            );
            return strtr($str, $tbl);
        }
        public static function MakeTag($tag_name, $attributes = null, $other_parameters = null, $close = true)
        {
            $a = Array();
            foreach($attributes as $key => $value)
            {
                $a[] = sprintf('%s="%s"', $key, $value);
            }
            $t = '<'.$tag_name;
            if(count($a) > 0)
            {
                $t .= ' '.implode(' ', $a);
            }
            if(!is_null($other_parameters))
            {
                $t .= ' '.trim($other_parameters);
            }
            if($close)
            {
                $t .= ' /';
            }
            $t .= '>';
            return $t;
        }
    }
    
    class MikronPageClass
    {
        
        private $mikron;

        public function __construct($mikron)
        {
            $this->mikron = $mikron;
        }

        public function getCurrentPage()
        {
            if(isset($_SERVER['REQUEST_URI']))
            {
                return $_SERVER['REQUEST_URI'];
            }
            if(isset($_SERVER['REDIRECT_URL']))
            {
                return $_SERVER['REDIRECT_URL'];
            }
            return $_SERVER['SCRIPT_NAME'];
        }

        public function StartBody($EnableGraphEffects = false)
        {

            static $body_started;
            if($body_started)
            {
                return null;
            }
            $body_started = true;
            ob_start();
            if(class_exists('drag_table'))
            {
                $drag_table = new drag_table();
            }
            getdifftime('start body');
            try
            {
               $this->mikron->EntityManager->CheckSave();
            }
            catch(Exception $ex)
            {
                CriticalError('Ошибка при CheckSave() в файле '.$ex->getFile().' в строке '.$ex->getLine().', '.$ex->getMessage(), null, true);
            }
            // $this->mikron->Counter->Counter();
        }

        // End document/завершение документа
        public function EndBody($usetemplate = true, $gzip = true)
        {
            getdifftime('end body');
            try
            {
                $this->EndBody_Function($usetemplate, $gzip);
            }
            catch(Exception $ex)
            {
                $message = $ex->getMessage();
                echo '<div class="mikroncms_error">Critical error:
                <font color="red">'.$message.'</font></div>';
            }
        }

        private function EndBody_Function(&$usetemplate, &$gzip)
        {

            static $isended = false;
            if($isended){exit;}else{$isended=true;}

            $miniBB_gzipper_in = ob_get_clean();
            $miniBB_gzipper_in .= "<!-- ".constant('RUN_TIME_KEY')." -->";

            // PagePrinted handlers
            $this->mikron->Handlers->PagePrintedHandlersRun($miniBB_gzipper_in);

            // Скрытые области к которым доступ могут получать
            // только авторизованные пользователи
            $mikron_na = '{{MIKRON_NEEDAUTH}}';

            if(strlen($miniBB_gzipper_in) < 1)
            {
                $miniBB_gzipper_in = 'Сайт пустой. Зайдите в админку,
                обновите схему и сделайте импорт данных.';
            }

            $html = '{{$BODY}}';
            if($usetemplate)
            {
                $html = null;
                // если это админка, то применяем особый стиль, который нельзя отредактировать в админке
                $adminstyle = constant('MIKRON_DIRECTORY').'/templates/admin/style.htm';
                if(constant('ADMIN_CENTER') && file_exists($adminstyle))
                {
                    $html = '{{$BODY}}';
                    $html = file_get_contents($adminstyle);
                }
                else
                {
                    $e = $this->mikron->Queries->Query('T_PAGESETTINGS');
                    $adr = $_SERVER['REQUEST_URI'];
                    $default_style = null;
                    // Шаблоны
                    while($item = $e->fetch())
                    {
                        $tadr = $item->address->value;
                        if($tadr == '*')
                        {
                            $default_style = $item->html->value;
                        }
                        else
                        {
                            $capture_this_style = false;
                            if($tadr == '/')
                            {
                                if($adr == '/')
                                {
                                    $capture_this_style = true;
                                }
                            }
                            else
                            {
                                $pos = strpos($adr, $tadr);
                                if(($pos !== false) && ($pos == 0))
                                {
                                    $capture_this_style = true;
                                }
                            }
                            if($capture_this_style)
                            {
                                $html = $item->html->value;
                                break;
                            }
                        }
                    }
                    if(is_null($html))
                    {
                        $html = $default_style;
                    }
                }
            }

            // Обработчик управляющих инструкций
            try
            {
               $miniBB_gzipper_in = translateOpIns($miniBB_gzipper_in, $html);
               $miniBB_gzipper_in = translateOpIns(null, $miniBB_gzipper_in);
            }
            Catch(Exception $ex)
            {
                $miniBB_gzipper_in = $ex->getMessage().' in file '.$ex->getFile().' on line '.$ex->getLine();
            }
            
            if(!constant('ADMIN_CENTER'))
            {
                for($i=0; $i < 3; $i++)
                {
                    if(strpos($miniBB_gzipper_in, '{{') === false)
                    {
                        break;
                    }
                    $miniBB_gzipper_in = translateOpIns(null, $miniBB_gzipper_in);
                }
            }

           $ldm = $this->mikron->TemplateMaker->smarty->left_delimiter;
           $rdm = $this->mikron->TemplateMaker->smarty->right_delimiter;
           $miniBB_gzipper_in = str_replace($ldm.'superliteral'.$rdm, null, $miniBB_gzipper_in);
           $miniBB_gzipper_in = str_replace($ldm.'/superliteral'.$rdm, null, $miniBB_gzipper_in);

            // PageComplete handlers
            $this->mikron->Handlers->PageCompleteHandlersRun($miniBB_gzipper_in);

            // If need gzip page
            if($gzip)
            {
                // If agent is support gzip-compression
                if(isset($_SERVER['HTTP_ACCEPT_ENCODING']))
                {
                    // Gzipp this page
                    $compressmethod = null;
                    if (strpos(' ' . $_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip') !== false) {$compressmethod = 'x-gzip';}
                    if (strpos(' ' . $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false) {$compressmethod = 'gzip';}
                    if($compressmethod != null)
                    {
                        $miniBB_gzipper_inlenn = strlen($miniBB_gzipper_in);
                        $miniBB_gzipper_out = gzencode($miniBB_gzipper_in, 4);
                        $miniBB_gzipper_lenn = strlen($miniBB_gzipper_out);
                        $miniBB_gzipper_in_strlen = strlen($miniBB_gzipper_in);
                        $gzpercent = 0;
                        if($miniBB_gzipper_in_strlen != 0)
                        {
                            $gzpercent = ($miniBB_gzipper_lenn / $miniBB_gzipper_in_strlen) * 100;
                        }
                        $percent = round($gzpercent);
                        $miniBB_gzipper_in = str_replace('<!- GZipper_Stats ->', 'Original: '.strlen($miniBB_gzipper_in).' GZipped: '.$miniBB_gzipper_lenn.' Compression: '.$percent.'%', $miniBB_gzipper_in);
                        $miniBB_gzipper_out = gzencode($miniBB_gzipper_in, 4);
                        header('Content-Encoding: '.$compressmethod);
                        echo $miniBB_gzipper_out;
                        return;
                    }
                }
            }

            // If gzip is not supported
            echo $miniBB_gzipper_in;
            ob_end_flush();

        }
    }


    class MikronTimer
    {
        private $time = null;

        public function __construct()
        {
            $this->reset();
        }

        public function elapsed()
        {
            $diff = 0;
            $time_end = self::getmicrotime();
            $diff = $time_end - $this->time;
            return round($diff, 4);
        }

        public function reset()
        {
            $this->time = self::getmicrotime();
        }

        
        public static function getmicrotime()
        {
            list($usec, $sec) = explode(" ", microtime());
            return ((float)$usec + (float)$sec);
        }
    }

    // сайты
    class site
    {
        private $v_sitename = null;
        private $v_dir = null;
        function sitename()
        {
            return $this->v_sitename;
        }
        function __construct($name, $directory)
        {
            $directory = realpath($directory);
            $this->v_sitename = $name;
            $site_need_dirs = Array();
            $site_need_files = Array();
            $site_need_dirs[] = $directory.'/private';
            $site_need_files[] = $directory.'/private/site.inc';
            $site_need_files[] = $directory.'/private/site_main.inc';
            $site_need_files[] = $directory.'/private/access.inc';
            foreach($site_need_dirs as $dir)
            {
                $dir = str_replace('\\', '/', $dir);
                if(!file_exists($dir) || !is_dir($dir))
                {
                    $dir_name = str_replace($_SERVER['DOCUMENT_ROOT'], '...', $dir);
                    // throw new Exception(sprintf('Site not contain directory %s', $dir_name));
                }
            }
            foreach($site_need_files as $file)
            {
                $file = str_replace('\\', '/', $file);
                if(!file_exists($file))
                {
                    $file_name = str_replace($_SERVER['DOCUMENT_ROOT'], '...', $file);
                    // throw new Exception(sprintf('Site not contain file %s', $file_name));
                }
            }
        }
    }

    class MikronSiteManager
    {
        public $DefaultSite;
        public $CurrentSite = null;
        public $sites = Array();

        public function __construct($mikron)
        {
            $this->DefaultSite = $mikron->Config->GetString('default_site');
            // Составление списка сайтов в системе
            $this->sites = Array();
            $sitesdir = constant('MIKRON_DIRECTORY').'/sites/';
            $dir = opendir($sitesdir);
            while ($d = readdir($dir))
            {
                if(is_dir($sitesdir.$d))
                {
                    switch($d)
                    {
                        case '.': case '..':
                            break;
                        default:
                            $this->sites[] = new site($d, $sitesdir.$d);
                            break;
                    }
                }
            }
            // текущий сайт
            $default_site = $this->DefaultSite;
            $this->CurrentSite = $this->sites[0];
            foreach($this->sites as $s)
            {
                if($s->sitename() == $default_site)
                {
                    $this->CurrentSite = $s;
                    break;
                }
            }
            $selsitename = null;
            if(isset($_COOKIE['currentsite']))
            {
                $selsitename = $_COOKIE['currentsite'];
            }
            // изменение текущего сайта
            if(isset($_REQUEST['changesite']))
            {
                // существует ли сайт
                reset($this->sites);
                foreach($this->sites as $site)
                {
                    if($site->sitename() == $_REQUEST['changesite'])
                    {
                        $selsitename = $_REQUEST['changesite'];
                        // запоминаем на целый год
                        setcookie('currentsite', $selsitename, time()+3600*24*365, '/');
                        break;
                    }
                }
            }
            if(!is_null($selsitename))
            {
                reset($this->sites);
                foreach($this->sites as $site)
                {
                    if($site->sitename() == $selsitename)
                    {
                        $this->CurrentSite = $site;
                        break;
                    }
                }
            }
        }
    }


    class DataObject
    {
        
        public $name = null;
        private $attributes = null;
        public $SourceXML = null;

        function Values()
        {
            return $this->attributes;
        }

        /**
        * Схема данных
        */
        private static $XSD = '<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="data">
    <xs:complexType>
      <xs:sequence>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element maxOccurs="unbounded" name="attr">
            <xs:complexType>
              <xs:simpleContent>
                <xs:extension base="xs:string">
                  <xs:attribute name="name" type="xs:string" use="required" />
                  <xs:attribute name="value" type="xs:string" use="optional" />
                </xs:extension>
              </xs:simpleContent>
            </xs:complexType>
          </xs:element>
          <xs:element name="list">
            <xs:complexType>
              <xs:sequence>
                <xs:element ref="data" minOccurs="0" maxOccurs="unbounded" />
              </xs:sequence>
              <xs:attribute name="name" type="xs:string" use="required" />
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:sequence>
      <xs:attribute name="name" type="xs:string" use="required" />
    </xs:complexType>
  </xs:element>
</xs:schema>';

        public function __construct($name = null, $xml = null)
        {
            if(!is_null($xml))
            {
                return $this->ReadXml($xml);
            }
            $this->name = $name;
        }

        public function SetString($name, $value)        
        {
            $this->attributes[$name] = $value;
        }

        public function SetGuid($name, $value)        
        {
            $this->attributes[$name] = $value;
        }

        public function SetList($name, $value)        
        {
            if(!is_array($value))
            {
                $method = __METHOD__;
                throw new Exception('Произошла ошибка в '.$method.'().');
            }
            $this->attributes[$name] = $value;
            $list = &$this->attributes[$name];
            return $list;
        }

        public function SetOADateTime($name, $value)        
        {
            global $mikron;
            if(!is_numeric($value))
            {
                $value = strtotime($value);
            }
            $value = $mikron->Tools->DateTime->ToOADate($value);
            $this->attributes[$name] = $value;
        }

        public function SetOADateTimeMSSQL($name, $value)        
        {
            global $mikron;
            if(!is_numeric($value))
            {
                $value = strtotime($value);
            }
            $value = $mikron->Tools->DateTime->ToOADateMSSQL($value);
            $this->attributes[$name] = $value;
        }

        public function GetOADateTimeMSSQL($name)        
        {
            if(!array_key_exists($name, $this->attributes))
            {
                throw new Exception("Атрибут '$name' не содержится в коллекции.");
            }
            global $mikron;
            $value = str_replace(',', '.', $this->attributes[$name]);
            return $mikron->Tools->DateTime->FromOADateMSSQL($value);
        }

        public function SetDateTime($name, $value)        
        {
            global $mikron;
            if(is_numeric($value))
            {
                $value = date($mikron->Constants->DateTimeFormat, (int)$value);
            }
            else
            {
                $value = date($mikron->Constants->DateTimeFormat, strtotime($value));
            }
            $value = strtotime($value);
            $this->attributes[$name] = $value;
        }

        public function SetInt($name, $value)        
        {
            $this->attributes[$name] = (int)$value;
        }
        
        /**
        * Recursive function
        * 
        * @param DOMDocument $doc
        * @param DOMElement $data
        * @param Array of DataObject $attributes
        */
        private static function Preserialize(&$doc, &$data, &$attributes)
        {
            if(!is_array($attributes))
            {
                return;
            }
            foreach($attributes as $name => $value)
            {
                if(is_array($value))
                {
                    $attr = $doc->createElement('list');
                    $attr->setAttribute('name', $name);
                    $data->appendChild($attr);
                    foreach($value as $DataObjectAttribute)
                    {
                        $innerAttrItem = $doc->createElement('data');
                        $innerAttrItem->setAttribute('name', $DataObjectAttribute->name);
                        self::Preserialize($doc, $innerAttrItem, $DataObjectAttribute->attributes);
                        $attr->appendChild($innerAttrItem);
                    }                                      
                }
                else
                {
                    $attr = $doc->createElement('attr');
                    $attr->setAttribute('name', $name);
                    $text = $doc->createTextNode($value);
                    $attr->appendChild($text);
                    $data->appendChild($attr);
                }
            }
        }
        
        /**
        * Сериализация
        * 
        * @param DataObject $dataObject
        * @return string
        */
        public static function Serialize(DataObject $dataObject)
        {
            $doc = new DOMDocument();
            $doc->formatOutput = true;
            $data = $doc->createElement('data');
            $data->setAttribute('name', $dataObject->name);
            self::Preserialize($doc, $data, $dataObject->attributes);
            $doc->appendChild($data);
            return $doc->SaveXML();
        }

        /**
        * Десериализация
        * 
        * @param mixed $xml Строка, содержащая XML
        * @return DataObject
        */
        public function Deserialize($xml)
        {
            $dataObject = new DataObject();
            dataObject.ReadXml($xml);
            return dataObject;
        }
        
        private function parseNode($root, $dataObject)
        {
            $obj = $root->childNodes;
            for ($i = 0; $i < $obj->length; $i++)
            {
                $item = $obj->item($i);
                if($item instanceof DOMElement)
                {
                    switch($item->nodeName)
                    {
                        case 'attr':
                            $name = $item->getAttribute('name');
                            $value = $item->textContent;
                            $dataObject->SetString($name, $value);
                            break;
                        case 'list':
                            $name = $item->getAttribute('name');
                            $subDataObject = $item->childNodes;
                            $items = Array();
                            for ($j = 0; $j < $subDataObject->length; $j++)
                            {
                                $sub_item = $subDataObject->item($j);
                                if($sub_item instanceof DOMElement)
                                {
                                    switch($sub_item->nodeName)
                                    {
                                        case 'data':
                                            $value = new DataObject($sub_item->getAttribute('name'));
                                            $this->parseNode($sub_item, $value);
                                            $items[] = $value;
                                            break;
                                    }
                                }
                            }
                            $dataObject->SetList($name, $items);
                            break;
                    }
                }
            }
        }

        public function ReadXml($xml)
        {
            $dom = new DOMDocument();
            $dom->loadXML($xml);

            $validation_result = $dom->schemaValidateSource(DataObject::$XSD);
            if(!$validation_result)
            {
                throw new MikronException('Произошла ошибка при валидации xml.', 1);
            }

            $this->SourceXML = $xml;
            $this->attributes = Array();
            $root = $dom->firstChild;

            $this->name = $root->getAttribute('name');
            $this->parseNode($root, $this);
        }

        function GetList($attr)
        {
            if(!array_key_exists($attr, $this->attributes))
            {
                throw new Exception("Атрибут '$attr' не содержится в коллекции.");
            }
            return $this->attributes[$attr];
        }

        public function GetGuid($attr)
        {
            if(!array_key_exists($attr, $this->attributes))
            {
                throw new Exception("Атрибут '$attr' не содержится в коллекции.");
            }
            return $this->attributes[$attr];
        }

        function GetString($attr)
        {
            if(!array_key_exists($attr, $this->attributes))
            {
                throw new Exception("Атрибут '$attr' не содержится в коллекции.");
            }
            return $this->attributes[$attr];
        }

        function GetDateTime($attr)
        {
            if(!array_key_exists($attr, $this->attributes))
            {
                throw new Exception("Атрибут '$attr' не содержится в коллекции.");
            }
            return $this->attributes[$attr];
        }

        function GetInt($attr)
        {
            if(!array_key_exists($attr, $this->attributes))
            {
                throw new Exception("Атрибут '$attr' не содержится в коллекции.");
            }
            return (int)$this->attributes[$attr];
        }

    }

    class MikronSchema
    {
        private $file = null, $name = null;
        public function file()
        {
            return $this->file;
        }
        public function name()
        {
            return $this->name;
        }
        public function __construct($file, $name)
        {
            if(!file_exists($file) || is_dir($file))
            {
                throw new Exception('Schema file not found '.$file);
            }
            $this->file = $file;
            $this->name = $name;
        }
    }

    class MikronSchemas
    {
        private $shemas = Array();
        private $mikron;
        public function __construct(MikronClass $mikron)
        {
            $this->mikron = $mikron;
            foreach($this->mikron->Config->GetList('system_schemas') as $systemSchema)
            {
                $schemaName = $systemSchema->name;
                $schemaFile = dirname($mikron->Config->FileName()).$systemSchema->getString('file');
                $this->Add($schemaFile, $schemaName);
            }
        }

        /**
        * Добавление файла схемы
        * 
        * @param mixed $file Полный путь к файлу
        * @param mixed $name Любое название
        */
        public function Add($file, $name)
        {
            $this->shemas[] = new MikronSchema($file, $name);
        }

        /**
        * Возвращает массив схем
        * 
        * @param string $by_file Если задан аттрибут $by_file, тогда функция вернет схему которая хранится в указанном файле, либо null если такой схемы нет
        */
        public function &Schemas($by_file = null)
        {
            reset($this->shemas);
            if(!is_null($by_file))
            {
                foreach($this->shemas as $scheme)
                {
                    if($scheme->file() == $by_file)
                    {
                        return $scheme;
                    }
                }
                return null;
            }
            return $this->shemas;
        }
    }
    
    /**
    * Конфигурационный файл на основе DataObject с добавленными
    * функциями записи и чтения конфигурации из XML-файла.
    */
    class MikronConfigManager extends DataObject
    {
        private $configurationFile = null;
        public function FileName()
        {
            return $this->configurationFile;
        }
        public function __construct()
        {
            $this->LoadFromFile(constant('CMS_DIRECTORY').'/config.xml');
        }
        private function LoadFromFile($xmlFile)
        {
            if(!file_exists($xmlFile) || is_dir($xmlFile))
            {
                throw new Exception(sprintf('Configuration file not found %s.', $xmlFile));
            }
            if(!is_readable($xmlFile))
            {
                throw new Exception(sprintf('Permission dennied to configuration file %s.', $xmlFile));
            }
            $xml = file_get_contents($xmlFile);
            parent::ReadXml($xml);
            $this->configurationFile = $xmlFile;
        }
        public function Save()
        {
            if(is_null($this->configurationFile))
            {
                throw new Exception('Configuration file not defined.');
            }
            file_put_contents($this->configurationFile, parent::Serialize($this), LOCK_EX);
        }
    }

?>